package com.shockweb.common.calculate.parse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.shockweb.common.calculate.CalculateParseException;
import com.shockweb.common.calculate.api.IFunction;
import com.shockweb.common.calculate.api.IParameter;
import com.shockweb.common.calculate.util.SimpleCalculate;
import com.shockweb.common.utils.ClassUtil;

/**
 * 初始化公式,表达式解析
 * @author pengminghua
 *
 */
public class ExpressionParse extends Object {

	private static String packageNames = "com.shockweb.commom.calculate.function";

	/**
	 * 设置表达式函数的加载目录
	 * @param packageNames
	 */
	public static void setPackageNames(String packageNames){
		ExpressionParse.packageNames = packageNames;
	}
	
	private static List<IFunction> funCache = new ArrayList<IFunction>();
	private static Map<String,IFunction> funCache2 = new HashMap<String,IFunction>();
	private static int funMaxLen = 0;
	
	static{
		try {
			funCache.clear();
			funCache2.clear();
			init();
		} catch (CalculateParseException e) {
		}
	}
	/**
	 * 表达式解析
	 */
	private ExpressionParse(){
	}
	
	/**
	 * 初始化
	 * @throws ConfigException
	 */
	private synchronized static void init()throws CalculateParseException{
		addFunction("open.calculate.function.Negative");
		addFunction("open.calculate.function.Reverse");
		addFunction("open.calculate.function.Abs");
		addFunction("open.calculate.function.Acos");
		addFunction("open.calculate.function.Asin");
		addFunction("open.calculate.function.Atan");
		addFunction("open.calculate.function.Cos");
		addFunction("open.calculate.function.Iif");
		addFunction("open.calculate.function.IndexOf");
		addFunction("open.calculate.function.Len");
		addFunction("open.calculate.function.Log");
		addFunction("open.calculate.function.Log10");
		addFunction("open.calculate.function.Lower");
		addFunction("open.calculate.function.Max");
		addFunction("open.calculate.function.Min");
		addFunction("open.calculate.function.Pow");
		addFunction("open.calculate.function.Random");
		addFunction("open.calculate.function.Sin");
		addFunction("open.calculate.function.Sqrt");
		addFunction("open.calculate.function.Square");
		addFunction("open.calculate.function.Sub");
		addFunction("open.calculate.function.Tan");
		addFunction("open.calculate.function.ToDecimal");
		addFunction("open.calculate.function.ToString");
		addFunction("open.calculate.function.Trim");
		addFunction("open.calculate.function.Upper");
		addFunction("open.calculate.function.Round");	
	}
	

	
	
	/**
	 * 添加一个函数
	 * @param className
	 * @throws CalculateParseException
	 */
	public synchronized static void addFunction(String className)throws  CalculateParseException{
		IFunction fun = null;
		try {
			fun = (IFunction)ClassUtil.getDefaultClassLoader().loadClass(className).newInstance();
		} catch (IllegalAccessException e) {
			throw new CalculateParseException("Add function class is error",e);
		} catch (InstantiationException e) {
			throw new CalculateParseException("Add function class is error",e);
		} catch (ClassNotFoundException e) {
			throw new CalculateParseException("Add function class is error",e);
		}
		if(!funCache2.containsKey(fun.getName())){
			funCache.add(fun);
			funCache2.put(fun.getName(),fun);
			if(fun.getName().length()>funMaxLen){
				funMaxLen = fun.getName().length();
			}
		}
	}
	/**
	 * 刷新支持的函数实例
	 * @throws CalculateParseException
	 */
	public synchronized static void refreshFunctions()throws CalculateParseException{
		if(funCache==null){
			funCache = new ArrayList<IFunction>();
			funCache2 = new HashMap<String,IFunction>();
		}else{
			funCache.clear();
			funCache2.clear();
		}
		try {
			ClassUtil loader = new ClassUtil();
			loader.findInPackages(packageNames.split("\\s*[,]\\s*"));
			Object[] classes = loader.getClasses().toArray();
			List<Object> funs = new ArrayList<Object>();
			for(int i=0;i<classes.length;i++){
				Class<?> type = (Class<?>)classes[i];
				if(IFunction.class.isAssignableFrom(type) && !type.isInterface()){
					funs.add(type.newInstance());
				}
			}
			funMaxLen = 0;
			for(int i=0;i<funs.size();i++){
				IFunction fun = (IFunction)funs.get(i);
				if(fun.getName().length()>funMaxLen){
					funMaxLen = fun.getName().length();
				}
			}
			for(int j=funMaxLen;j>=1;j--){
				for(int i=0;i<funs.size();i++){
					IFunction fun = (IFunction)funs.get(i);
					if(fun.getName().length()==j){
						funCache.add(fun);
						funCache2.put(fun.getName(),fun);
					}
				}
			}
		} catch (Exception e) {
			throw new CalculateParseException("Load route '" + packageNames + "' self definition function mistake",e);
		}
		init();
	}
	
	/**
	 * 根据表达式组建运算的tree结构
	 * @param expression
	 * @param parameter
	 * @param divScale
	 * @param option
	 * @return ExpressionNode
	 * @throws CalculateParseException
	 */
	public static ExpressionNode parse(String expression,IParameter parameter,int divScale,boolean option)throws CalculateParseException{
		ExpressionNode node = new ExpressionNode(expression.replaceAll(" ",""));
		if(option){
			parseForRepeat(node,parameter,divScale);
		}else{
			parseForSimpleness(node,parameter,divScale);
		}
		return node;
	}


	/**
	 * 判断expression第index个字符前一个key是否为函数
	 * @param index
	 * @param expression
	 * @return IFunction
	 */
	private static IFunction getPrevFun(int index,StringBuffer expression){
		int i = 0;
		if(index == 0){
			return null;
		}else{
			int startIndex = index - funMaxLen;
			if(startIndex<0){
				 i = -startIndex;
				 startIndex = index - funMaxLen + i;
			}
			String currStr = expression.substring(startIndex,index);
			IFunction fun = getFunction(currStr);
			while(fun==null && i<funMaxLen){
				i++;
				startIndex = index - funMaxLen + i;
				currStr = expression.substring(startIndex,index);
				fun = getFunction(currStr);
			}
			if(i==funMaxLen){
				return null;
			}else{
				return fun;
			}
		}
	}
	
	/**
	 * 比较是否为函数名
	 * @param name
	 * @return IFunction
	 */
	private synchronized static IFunction getFunction(String name){
		return funCache2.get(name);
	}


	/**
	 * 判断表达式是否为函数
	 * @param key
	 * @return IFunction
	 */
	private static IFunction getFirstCalculator(String key)throws CalculateParseException{
		IFunction rtn = null;
		StringBuffer sb = new StringBuffer(key);
		for(int i=0;i<funCache.size();i++){
			IFunction fun = (IFunction)funCache.get(i);
			if(key.startsWith(fun.getName() + "(") && getBracketEndIndex(sb,0)==key.length()-1){
				rtn = fun;
				break;
			}
		}
		return rtn;
	}
	
	
	/**
	 * 表达式转换,去除括号
	 * @param node
	 * @param parameter
	 * @param divScale
	 * @throws CalculateParseException
	 */
	private static void parseForSimpleness(ExpressionNode node,IParameter parameter,int divScale)throws CalculateParseException{
		try{
			String nodeKey = node.getKey();
			if(node.getFunction()==null){
				node.setFunction(getFirstCalculator(nodeKey));
			}
			if(node.getFunction()!=null){
				//有计算器为表达式函数
				IFunction fun = (IFunction)node.getFunction();
				int startIndex = fun.getName().length();
				int endIndex = nodeKey.length()-1;
				if(startIndex<endIndex){
					StringBuffer expression = new StringBuffer(nodeKey.substring(startIndex+1,endIndex));
					startIndex = 0;
					endIndex = 0;
					while(true){
						endIndex = getCommaEndIndex(expression,startIndex);
						if(endIndex>=0 && endIndex!=startIndex){
							String key = expression.substring(startIndex,endIndex);
							ExpressionNode childNode = new ExpressionNode(key);
							node.addNode(childNode);
							startIndex = endIndex+1;
						}else{
							break;
						}
					}
					if(node.getNodeSize()!=fun.getParamCount()){
						throw new CalculateParseException("Function '" + node.getKey() + "' ginseng quantity is inconsistent");
					}
					node.setExpression(expression);
				}
			}else{
				StringBuffer expression = new StringBuffer(node.getKey());
				int index = 0;
				int startIndex = 0;
				int endIndex = 0;
				//没有计算器表示为表达式
				while(true){
					int strIndexStart = expression.indexOf("\"",index);
					if(index < expression.indexOf("(")){
						index = expression.indexOf("(");
					}else{
						if(strIndexStart>=0){
							index = expression.indexOf("\"",strIndexStart+1)+1;
						}
						index = expression.indexOf("(",index);
					}
					if(index>=0){
						IFunction fun = getPrevFun(index,expression);
						startIndex = index;
						endIndex = getBracketEndIndex(expression,index);
						if(fun!=null){
							startIndex-= fun.getName().length();
							String key = expression.substring(startIndex,endIndex+1);
							ExpressionNode childNode = new ExpressionNode(key);
							childNode.setFunction(fun);
							node.addNode(childNode);
							String param = "_" + (node.getNodeSize()-1) + "_";
							expression.replace(startIndex,endIndex+1,param);
							index += param.length();
						}else{
							index += 1;
						}
					}else{
						break;
					}
				}
				node.setExpression(expression);
				node.setSimpleCalculate(new SimpleCalculate(expression,parameter,divScale));
			}
			for(int i=0;i<node.getNodeSize();i++){
				parseForSimpleness(node.getNode(i),parameter,divScale);
			}
		}catch(CalculateParseException e){
			throw e;
		}catch(Exception e){
			throw new CalculateParseException("Analytical expression '" + node.getKey() + "' makes mistakes",e);
		}
	}
	
	/**
	 * 执行重复表达式
	 * @param node
	 * @param parameter
	 * @param divScale
	 * @throws CalculateParseException
	 */
	private static void parseForRepeat(ExpressionNode node,IParameter parameter,int divScale)throws CalculateParseException{
		try{
			String nodeKey = node.getKey();
			if(node.getFunction()==null){
				node.setFunction(getFirstCalculator(nodeKey));
			}
			if(node.getFunction()!=null){
				//有计算器为表达式函数
				IFunction fun = (IFunction)node.getFunction();
				int startIndex = fun.getName().length();
				int endIndex = nodeKey.length()-1;
				if(startIndex<endIndex){
					StringBuffer expression = new StringBuffer(nodeKey.substring(startIndex+1,endIndex));
					startIndex = 0;
					endIndex = 0;
					while(true){
						endIndex = getCommaEndIndex(expression,startIndex);
						if(endIndex>=0 && endIndex!=startIndex){
							String key = expression.substring(startIndex,endIndex);
							ExpressionNode childNode = new ExpressionNode(key);
							node.addNode(childNode);
							startIndex = endIndex+1;
						}else{
							break;
						}
					}
					if(node.getNodeSize()!=fun.getParamCount()){
						throw new CalculateParseException("Letter '" + nodeKey + "' ginseng quantity is inconsistent");
					}
					node.setExpression(expression);
				}
			}else{
				StringBuffer expression = new StringBuffer(nodeKey);
				int index = 0;
				int startIndex = 0;
				int endIndex = 0;
				//没有计算器表示为表达式
				while(true){
					int strIndexStart = expression.indexOf("\"",index);
					if(strIndexStart>=0){
						index = expression.indexOf("\"",strIndexStart+1)+1;
					}
					index = expression.indexOf("(",index);
					if(index>=0){
						IFunction fun = getPrevFun(index,expression);
						startIndex = index;
						endIndex = getBracketEndIndex(expression,index);
						if(fun!=null){
							startIndex-= fun.getName().length();
							String key = expression.substring(startIndex,endIndex+1);
							ExpressionNode childNode = new ExpressionNode(key);
							childNode.setFunction(fun);
							node.addNode(childNode);
						}else{
							String key = expression.substring(startIndex+1,endIndex);
							ExpressionNode childNode = new ExpressionNode(key);
							node.addNode(childNode);
						}
						String param = "_" + (node.getNodeSize()-1) + "_";
						expression.replace(startIndex,endIndex+1,param);
						index += param.length();
					}else{
						break;
					}
				}
				node.setExpression(expression);
				node.setSimpleCalculate(new SimpleCalculate(expression,parameter,divScale));
			}
			for(int i=0;i<node.getNodeSize();i++){
				parseForRepeat(node.getNode(i),parameter,divScale);
			}
		}catch(CalculateParseException e){
			throw e;
		}catch(Exception e){
			throw new CalculateParseException("Analytical expression '" + node.getKey() + "' makes mistakes",e);
		}

	}

	/**
	 * 获取,的结束位置
	 * @param expression
	 * @param index
	 * @return int
	 */
	public static int getCommaEndIndex(StringBuffer expression,int index)throws CalculateParseException{
		int rtn = -1;
		int count1 = 0;
		int count2 = 0;
		int i = index;
		for(;i<expression.length();i++){
			char c = expression.charAt(i);
			if(c=='('){
				count1++;
			}else if(c==')'){
				count2++;
			}
			if(c==',' && count1==count2){
				break;
			}
		}
		if(count1==count2){
			rtn = i;
		}
		if(rtn == -1){
			throw new CalculateParseException("Be short of ')' OR ','");
		}else{
			return rtn;
		}
	}
  
	/**
	 * 获取)的结束位置
	 * @param expression
	 * @param index
	 * @return int
	 */
 	private static int getBracketEndIndex(StringBuffer expression,int index)throws CalculateParseException{
 		int rtn = -1;
 		int count1 = 0;
 		int count2 = 0;
 		for(int i=index;i<expression.length();i++){
			char c = expression.charAt(i);
			if(c=='('){
				count1++;
			}else if(c==')'){
				count2++;
			}
			if(count1==count2 && count1>0){
				rtn = i;
				break;
			}
 		}
 		if(rtn == -1){
 			throw new CalculateParseException("Be short of ')'");
 		}else{
 			return rtn;
 		}
 	}
}

 